﻿#pragma once

namespace util
{
	template <typename T>
	class vector
	{
	private:
		T* arr;
		size_t size;
		size_t alloc;

	public:
		vector()
			: size(0),
			  alloc(8)
		{
			arr = static_cast<T*>(malloc(alloc * sizeof(T)));
		}

		vector(const size_t size)
			: size(size),
			  alloc(size + (size >> 1))
		{
			arr = static_cast<T*>(malloc(alloc * sizeof(T)));
		}

		~vector()
		{
			free(arr);
			arr = nullptr;
		}

		vector(const vector& other)
			: size(other.size),
			  alloc(other.alloc)
		{
			arr = malloc(alloc * sizeof(T));
			memcpy(arr, other.arr, size * sizeof(T));
		}

		vector(vector&& other) noexcept
			: arr(other.arr),
			  size(other.size),
			  alloc(other.alloc)
		{
		}

		vector& operator=(const vector& other)
		{
			if (this == &other)
				return *this;
			size = other.size;
			alloc = other.alloc;
			arr = malloc(alloc * sizeof(T));
			memcpy(arr, other.arr, size * sizeof(T));
			return *this;
		}

		vector& operator=(vector&& other) noexcept
		{
			if (this == &other)
				return *this;
			arr = other.arr;
			size = other.size;
			alloc = other.alloc;
			return *this;
		}

		T& operator[](size_t index)
		{
			return arr[index];
		}

		void push(T elt)
		{
			if (size == alloc) {
				alloc += (alloc >> 1); /* Increase size by 50% */
				arr = static_cast<T*>(realloc(arr, alloc * sizeof(T)));
			}
			arr[size++] = elt;
		}

		T pop()
		{
			return arr[size--];
		}

		void erase(size_t index)
		{
			if (index == size) {
				pop();
			}
			else {
				memmove(&(arr[index]), &(arr[index+1]),
					sizeof(T) * size - index - 1);
				size--;
			}
		}

		size_t length() const
		{
			return size;
		}

		T* data()
		{
			return arr;
		}

	};
}
